﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using OpenPasteSpider.sourcemodel;
using Z.EntityFramework.Plus;

namespace OpenPasteSpider.Controllers
{
    /// <summary>
    /// 
    /// </summary>
    [ApiController]
    [Route("/api/spider/upload/[action]")]
    public class APIUploadController : IBaseController
    {

        private IOpenPasteSpiderDbContext _dbContext;
        private readonly SpiderConfig _config;
        private readonly PublicModelHelper _modelHelper;
        /// <summary>
        /// 
        /// </summary>
        public APIUploadController(
            IOpenPasteSpiderDbContext dbContext,
            IOptions<SpiderConfig> config,
            PublicModelHelper modelHelper)
        {
            _dbContext = dbContext;
            _config = config.Value;
            _modelHelper = modelHelper;
        }


        /// <summary>
        /// 读取模式对应的文件夹的内容
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private string _readPathByModel(int model)
        {
            if (model == 0)
            {
                return "static";
            }
            if (model == 1)
            {
                return "source";
            }
            return "publish";
        }


        /// <summary>
        /// 读取配置信息 
        /// </summary>
        /// <param name="serviceid">哪个服务</param>
        /// <param name="model">1源码 2发布文件</param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<List<AsyncConfigListDto>> config(int serviceid, int model = 2)
        {
            var userid = base.ReadLoginUserId();

            //判断是读取所有的服务，还是读取有权限的服务 这里要缓存下


            var query = await _dbContext.AsyncConfig.Where(t => t.ServiceId == serviceid && t.IsEnable).AsNoTracking().ToListAsync();

            var list = ObjectMapper.Map<List<AsyncConfig>, List<AsyncConfigListDto>>(query);

            //这里需要把服务端的文件夹信息返回给前端

            return list;
        }


        /// <summary>
        /// 读取项目信息 包括所在信息和配置列表
        /// </summary>
        /// <param name="serviceid"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<dynamic> info(int serviceid, int model = 2)
        {

            var userid = base.ReadLoginUserId();



            var query = await _dbContext.AsyncConfig.Where(t => t.ServiceId == serviceid && t.IsEnable).AsNoTracking().ToListAsync();

            var list = ObjectMapper.Map<List<AsyncConfig>, List<AsyncConfigListDto>>(query);

            var servicedto = await _modelHelper.ItemServiceInfo(serviceid, _dbContext);

            return new
            {
                service = servicedto,
                configs = list,
                uploadpath = $"{_config.WorkDir}{_readPathByModel(model)}/{servicedto.Project.Code}/{servicedto.Code}"
            };
        }

        /// <summary>
        /// 上传文件完成后调用，用于增加文件版本号，非镜像版本号！
        /// </summary>
        /// <param name="serviceid"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<string> addversion(int serviceid)
        {
            var userid = base.ReadLoginUserId();

            await _dbContext.ServiceInfo.Where(x => x.Id == serviceid).UpdateAsync(x=>new projectmodel.ServiceInfo { FileVersion=x.FileVersion+1 });

            return "更新文件版本号成功！";
        }



        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="serviceid"></param>
        /// <param name="model">1源码模式 2发布模式</param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<dynamic> drop(int serviceid, int model = 2)
        {

            var userid = base.ReadLoginUserId();


            var result = false;
            var msg = String.Empty;
            if (base.Request.Form != null)
            {
                var servicedto = await _modelHelper.ItemServiceInfo(serviceid, _dbContext);

                //var project = _dbContext.ProjectInfo.Where(x => x.Id == serviceid).AsNoTracking().FirstOrDefault();

                if (servicedto == null || servicedto == default)
                {
                    throw new PasteCodeException("当前项目不存在");
                }

                var proot = $"{_config.WorkDir}{_readPathByModel(model)}/{servicedto.Project.Code}/{servicedto.Code}";

                if (!String.IsNullOrEmpty(servicedto.DirectPath))
                {
                    proot = servicedto.DirectPath;
                }

                //默认当前时区
                long lastMillSecond = 0;

                var fullPath = String.Empty;
                //这里还需要换算时差

                if (base.Request.Form.ContainsKey("utctime"))
                {
                    long.TryParse(base.Request.Form["utctime"], out var utctimestamp);
                    if (utctimestamp != 0)
                    {
                        lastMillSecond = utctimestamp + (long)TimeZoneInfo.Local.BaseUtcOffset.TotalMilliseconds;
                    }
                }
                else
                {
                    if (base.Request.Form.ContainsKey("lastModified"))
                    {
                        long.TryParse(base.Request.Form["lastModified"], out lastMillSecond);
                    }
                }
                if (base.Request.Form.ContainsKey("fullPath"))
                {
                    fullPath = base.Request.Form["fullPath"].ToString();
                }
                if (lastMillSecond == 0)
                {
                    lastMillSecond = DateTime.Now.ToUnixTimeMilliseconds();
                }

                if (base.Request.Form.Files != null)
                {
                    if (base.Request.Form.Files.Count > 0)
                    {
                        for (var k = 0; k < base.Request.Form.Files.Count; k++)
                        {
                            var finput = base.Request.Form.Files[k];
                            var save = $"{proot}{fullPath}";
                            var path = System.IO.Path.GetDirectoryName(save);
                            if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); }
                            System.IO.File.Delete(save);
                            using (System.IO.FileStream fs = new System.IO.FileStream(save, System.IO.FileMode.Create))
                            {
                                finput.CopyTo(fs);
                                fs.Flush();
                                fs.Dispose();
                            }
                            //var finfo = new System.IO.FileInfo(save);
                            //finfo.LastWriteTime = lastMillSecond.ToDateTimeFromMilliseconds();
                            result = true;
                            msg = save;
                        }

                    }
                }

            }

            return new
            {
                result = result,
                msg = msg
            };
        }


        /// <summary>
        /// 读取项目文件的信息
        /// </summary>
        /// <param name="serviceid"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<dynamic> read(int serviceid, int model = 2)
        {
            var servicedto = await _modelHelper.ItemServiceInfo(serviceid, _dbContext);
            if (servicedto == null || servicedto == default)
            {
                throw new PasteCodeException("没有这个服务，请重新提交！");
            }


            var userid = base.ReadLoginUserId();

            //var project = await _dbContext.ProjectInfo.Where(x => x.Id == serviceid).AsNoTracking().FirstOrDefaultAsync();
            var path = $"{_config.WorkDir}{_readPathByModel(model)}/{servicedto.Project.Code}/{servicedto.Code}/";

            if (!String.IsNullOrEmpty(servicedto.DirectPath))
            {
                path = $"{servicedto.DirectPath}/";
            }

            var list = new List<DropFileItem>();
            if (System.IO.Directory.Exists(path))
            {
                var igors = await _dbContext.AsyncConfig.Where(x => x.ServiceId == serviceid && x.Ignore).Select(x => x.FileName).AsNoTracking().ToListAsync();
                if (igors == null || igors == default)
                {
                    igors = new List<string>();
                }
                ReadFile(path, list, path, igors);
            }
            return list;
        }


        /// <summary>
        /// 删除项目文件，不包括忽略的文件
        /// </summary>
        /// <param name="serviceid"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        [HttpPost]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "view" })]
        public async Task<int> remove(int serviceid, int model = 2)
        {
            var servicedto = await _modelHelper.ItemServiceInfo(serviceid, _dbContext);
            if (servicedto == null || servicedto == default)
            {
                throw new PasteCodeException("当前项目不存在");
            }

            if(servicedto.FileModel == 3)
            {
                throw new PasteCodeException("服务的文件模式为镜像模式的时候，不需要更新文件！");
            }

            var userid = base.ReadLoginUserId();



            var backupdir = $"{_config.WorkDir}{_readPathByModel(model)}/{servicedto.Project.Code}/{servicedto.Code}_backup";
            if (!System.IO.Directory.Exists(backupdir))
            {
                System.IO.Directory.CreateDirectory(backupdir);
            }

            var proot = $"{_config.WorkDir}{_readPathByModel(model)}/{servicedto.Project.Code}/{servicedto.Code}";
            var query = await _dbContext.AsyncConfig.Where(t => t.ServiceId == serviceid && t.IsEnable && t.Ignore && !t.IsDirectory).AsNoTracking().ToListAsync();
            if (query != null && query.Any())
            {
                //是否需要复制到备份文件夹内
                foreach (var item in query)
                {
                    var filepath = $"{proot}{item.FileName}";
                    if (System.IO.File.Exists(filepath))
                    {
                        //需要确认文件夹是否存在
                        var newdir = System.IO.Path.GetDirectoryName($"{backupdir}{item.FileName}");
                        if (!System.IO.Directory.Exists(newdir)) { System.IO.Directory.CreateDirectory(newdir); }
                        //如果有多级目录，会有问题
                        System.IO.File.Copy($"{proot}{item.FileName}", $"{backupdir}{item.FileName}");
                    }
                }
            }
            //删除旧的文件夹
            System.IO.Directory.Delete(proot, true);

            //创建文件夹，复制回去
            if (!System.IO.Directory.Exists(proot)) { System.IO.Directory.CreateDirectory(proot); }

            //把忽略的文件复制回去
            if (query != null && query.Any())
            {
                //是否需要复制到备份文件夹内
                foreach (var item in query)
                {
                    var filepath = $"{backupdir}{item.FileName}";
                    if (System.IO.File.Exists(filepath))
                    {
                        //需要确认文件夹是否存在
                        var newdir = System.IO.Path.GetDirectoryName($"{proot}{item.FileName}");
                        if (!System.IO.Directory.Exists(newdir)) { System.IO.Directory.CreateDirectory(newdir); }
                        //如果有多级目录，会有问题
                        System.IO.File.Copy(filepath, $"{proot}{item.FileName}");
                    }
                }
            }

            //删除备份的文件
            if (query != null && query.Any())
            {
                //是否需要复制到备份文件夹内
                foreach (var item in query)
                {
                    var filepath = $"{backupdir}{item.FileName}";
                    if (System.IO.File.Exists(filepath))
                    {
                        System.IO.File.Delete(filepath);
                    }
                }
            }


            return 1;
        }


        /// <summary>
        /// 读取文件夹的文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="list"></param>
        /// <param name="root"></param>
        /// <param name="ignorelist"></param>
        private void ReadFile(string path, List<DropFileItem> list, string root, List<string> ignorelist)
        {
            if (path.Contains(@"\")) { path = path.Replace(@"\", "/"); }
            if (path.Contains("//")) { path = path.Replace("//", "/"); }
            if (System.IO.Directory.Exists(path))
            {
                var relativepath = ReadRelativePath(root, path);
                // /开头/结尾
                if (!ignorelist.Contains(relativepath))
                {
                    var dir = new System.IO.DirectoryInfo(path);
                    var dirs = dir.GetDirectories();
                    foreach (var item in dirs)
                    {
                        ReadFile(CombinePath(path, item.Name), list, root, ignorelist);
                    }
                    var files = dir.GetFiles();
                    foreach (var item in files)
                    {
                        var _stream = item.OpenRead();
                        var one = new DropFileItem()
                        {
                            fullPath = ReadRelativePath(root, item.DirectoryName) + item.Name,
                            lastModified = item.LastWriteTime.ToUnixTimeMilliseconds(),//当前时区的时间戳
                            name = item.Name,
                            utctime = item.LastWriteTime.ToUtcMilliSeconds(),
                            md5 = _readmd(_stream)
                        };
                        _stream.Close();
                        _stream.Dispose();
                        list.Add(one);
                    }
                }
                else
                {
                    Console.WriteLine($"path:{path} ignore!");
                }
            }
            else
            {
                Console.WriteLine($"path:{path} not exists");
            }
        }

        /// <summary>
        /// 读取文件的文件码
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        private string _readmd(System.IO.FileStream file)
        {
            using var md5 = MD5.Create();
            var filekey = BitConverter.ToString(md5.ComputeHash(file)).Replace("-", "").ToLower();
            md5.Dispose();
            return filekey;
        }

        /// <summary>
        /// 合并路径
        /// </summary>
        /// <param name="headpath"></param>
        /// <param name="footpath"></param>
        /// <returns></returns>
        private string CombinePath(string headpath, string footpath)
        {

            if (headpath.Contains(@"\\"))
            {
                headpath = headpath.Replace(@"\\", "/");
            }
            if (headpath.Contains("//"))
            {
                headpath = headpath.Replace("//", "/");
            }
            if (headpath.Contains(@"\"))
            {
                headpath = headpath.Replace(@"\", "/");
            }
            if (!headpath.StartsWith("/")) { headpath = "/" + headpath; }
            if (!headpath.EndsWith("/")) { headpath = headpath + "/"; }


            if (footpath.Contains(@"\\"))
            {
                footpath = footpath.Replace(@"\\", "/");
            }
            if (footpath.Contains("//"))
            {
                footpath = footpath.Replace("//", "/");
            }
            if (footpath.Contains(@"\"))
            {
                footpath = footpath.Replace(@"\", "/");
            }
            if (footpath.EndsWith("/"))
            {
                footpath = footpath + "/";
            }

            var newpath = $"{headpath}{footpath}";
            if (newpath.Contains("//"))
            {
                return newpath.Replace("//", "/");
            }
            return newpath;

        }

        /// <summary>
        /// 获取相对路径
        /// </summary>
        /// <param name="rootpath"></param>
        /// <param name="fullpath"></param>
        /// <returns></returns>
        private string ReadRelativePath(string rootpath, string fullpath)
        {
            //window的时候有问题 
            //System.Console.WriteLine($"{rootpath} --- {fullpath}");
            // /spider/publish/package/main/ --- D:\keeper\publish\package\main\MigratoryManage\task\static\h-ui\images\verticalTab


            if (fullpath.Contains(":"))
            {
                fullpath = fullpath.Split(":")[1];
            }
            if (fullpath.Contains(@"\\"))
            {
                fullpath = fullpath.Replace(@"\\", "/");
            }
            if (fullpath.Contains("//"))
            {
                fullpath = fullpath.Replace("//", "/");
            }
            if (fullpath.Contains(@"\"))
            {
                fullpath = fullpath.Replace(@"\", "/");
            }
            if (!fullpath.StartsWith("/"))
            {
                fullpath = "/" + fullpath;
            }
            if (!fullpath.EndsWith("/"))
            {
                fullpath = fullpath + "/";
            }

            if (rootpath.Contains(@"\\"))
            {
                rootpath = rootpath.Replace(@"\\", "/");
            }
            if (rootpath.Contains("//"))
            {
                rootpath = rootpath.Replace("//", "/");
            }
            if (rootpath.Contains(@"\"))
            {
                rootpath = rootpath.Replace(@"\", "/");
            }
            if (!rootpath.StartsWith("/"))
            {
                rootpath = "/" + rootpath;
            }
            if (!rootpath.EndsWith("/"))
            {
                rootpath = rootpath + "/";
            }
            if (fullpath.Contains(rootpath))
            {
                var relapath = fullpath.Substring(rootpath.Length);
                if (!relapath.StartsWith("/"))
                {
                    relapath = "/" + relapath;
                }
                if (!relapath.EndsWith("/"))
                {
                    relapath = relapath + "/";
                }
                return relapath;
            }
            else
            {
                return "/";
            }
        }


    }
}
